"""
D-Bus接口信息收集器

负责从OpenBMC代码仓库中收集D-Bus接口信息
"""

import os
import logging
from pathlib import Path
from typing import List, Dict, Set
from tqdm import tqdm
from data_structures import DBusInterface, AnalysisResult
from yaml_parser import YAMLParser


class InterfaceCollector:
    """D-Bus接口信息收集器"""
    
    def __init__(self):
        """初始化收集器"""
        self.logger = logging.getLogger(__name__)
        self.yaml_parser = YAMLParser()
        
        # 公共接口模式
        self.public_patterns = [
            'xyz.openbmc_project',
            'org.freedesktop.DBus',
            'org.freedesktop.SystemManager',
        ]
        
        # 厂商特定模式（需要排除）
        self.vendor_patterns = [
            'com.intel',
            'com.ibm', 
            'com.facebook',
            'com.microsoft',
            'com.google',
            'com.ampere',
            'com.nvidia',
            'com.amd',
            'com.qualcomm',
            'com.broadcom',
            'org.open_power'  # 虽然是开放标准，但不是通用BMC接口
        ]
    
    def collect_phosphor_interfaces(self, phosphor_path: str) -> AnalysisResult:
        """
        从phosphor-dbus-interfaces仓库收集接口信息
        
        Args:
            phosphor_path: phosphor-dbus-interfaces仓库路径
            
        Returns:
            分析结果
        """
        result = AnalysisResult()
        
        yaml_dir = Path(phosphor_path) / "yaml"
        if not yaml_dir.exists():
            error_msg = f"找不到YAML目录: {yaml_dir}"
            self.logger.error(error_msg)
            result.add_error(error_msg)
            return result
        
        self.logger.info("开始扫描phosphor-dbus-interfaces...")
        
        # 扫描所有YAML接口文件
        interfaces = self.yaml_parser.scan_yaml_directory(str(yaml_dir))
        
        # 过滤和处理接口
        self.logger.info("过滤公共接口...")
        for interface in tqdm(interfaces, desc="处理接口"):
            # 过滤公共接口
            if self._is_public_interface(interface):
                interface.is_public = True
                result.add_interface(interface)
            else:
                interface.is_public = False
                # 仍然添加到结果中，但标记为非公共
                result.add_interface(interface)
        
        self.logger.info(f"收集完成: 总接口数 {result.total_interfaces}, 公共接口数 {result.public_interfaces}")
        return result
    
    def collect_from_multiple_repos(self, repo_paths: Dict[str, str]) -> AnalysisResult:
        """
        从多个仓库收集接口信息
        
        Args:
            repo_paths: 仓库路径字典 {仓库名: 路径}
            
        Returns:
            合并的分析结果
        """
        combined_result = AnalysisResult()
        
        for repo_name, repo_path in repo_paths.items():
            self.logger.info(f"正在处理仓库: {repo_name}")
            
            if repo_name == "phosphor-dbus-interfaces":
                result = self.collect_phosphor_interfaces(repo_path)
            else:
                # 对于其他仓库，尝试查找YAML文件
                result = self._collect_from_generic_repo(repo_path, repo_name)
            
            # 合并结果
            self._merge_results(combined_result, result)
        
        return combined_result
    
    def _collect_from_generic_repo(self, repo_path: str, repo_name: str) -> AnalysisResult:
        """
        从通用仓库收集接口信息
        
        Args:
            repo_path: 仓库路径
            repo_name: 仓库名称
            
        Returns:
            分析结果
        """
        result = AnalysisResult()
        repo_path_obj = Path(repo_path)
        
        if not repo_path_obj.exists():
            error_msg = f"仓库路径不存在: {repo_path}"
            self.logger.error(error_msg)
            result.add_error(error_msg)
            return result
        
        # 查找YAML文件
        yaml_files = list(repo_path_obj.rglob("*.yaml"))
        interface_files = [f for f in yaml_files if 'interface' in f.name]
        
        if not interface_files:
            warning_msg = f"在仓库 {repo_name} 中未找到接口YAML文件"
            self.logger.warning(warning_msg)
            result.add_warning(warning_msg)
            return result
        
        self.logger.info(f"在 {repo_name} 中找到 {len(interface_files)} 个接口文件")
        
        for yaml_file in tqdm(interface_files, desc=f"处理 {repo_name}"):
            interface = self.yaml_parser.parse_interface_yaml(str(yaml_file))
            if interface:
                interface.is_public = self._is_public_interface(interface)
                result.add_interface(interface)
        
        return result
    
    def _is_public_interface(self, interface: DBusInterface) -> bool:
        """
        判断接口是否为公共接口
        
        Args:
            interface: 接口对象
            
        Returns:
            是否为公共接口
        """
        interface_name = interface.name.lower()
        
        # 检查是否匹配公共模式
        for pattern in self.public_patterns:
            if interface_name.startswith(pattern.lower()):
                # 进一步检查是否包含厂商特定内容
                for vendor_pattern in self.vendor_patterns:
                    if vendor_pattern.lower() in interface_name:
                        return False
                return True
        
        # 检查是否为厂商特定接口
        for vendor_pattern in self.vendor_patterns:
            if interface_name.startswith(vendor_pattern.lower()):
                return False
        
        # 默认情况下，如果不确定，倾向于认为是公共接口
        return True
    
    def _merge_results(self, target: AnalysisResult, source: AnalysisResult):
        """
        合并分析结果
        
        Args:
            target: 目标结果
            source: 源结果
        """
        # 合并接口列表
        for interface in source.interfaces:
            target.add_interface(interface)
        
        # 合并错误和警告
        target.errors.extend(source.errors)
        target.warnings.extend(source.warnings)
    
    def filter_interfaces_by_criteria(self, interfaces: List[DBusInterface], 
                                    **criteria) -> List[DBusInterface]:
        """
        根据条件过滤接口
        
        Args:
            interfaces: 接口列表
            **criteria: 过滤条件
                - public_only: bool, 仅公共接口
                - categories: List[str], 指定分类
                - namespaces: List[str], 指定命名空间
                - has_methods: bool, 必须有方法
                - has_properties: bool, 必须有属性
                - has_signals: bool, 必须有信号
                
        Returns:
            过滤后的接口列表
        """
        filtered = interfaces.copy()
        
        # 仅公共接口
        if criteria.get('public_only', False):
            filtered = [i for i in filtered if i.is_public]
        
        # 指定分类
        categories = criteria.get('categories')
        if categories:
            filtered = [i for i in filtered if i.category in categories]
        
        # 指定命名空间
        namespaces = criteria.get('namespaces')
        if namespaces:
            filtered = [i for i in filtered if i.namespace in namespaces]
        
        # 必须有方法
        if criteria.get('has_methods', False):
            filtered = [i for i in filtered if i.method_count > 0]
        
        # 必须有属性
        if criteria.get('has_properties', False):
            filtered = [i for i in filtered if i.property_count > 0]
        
        # 必须有信号
        if criteria.get('has_signals', False):
            filtered = [i for i in filtered if i.signal_count > 0]
        
        return filtered
    
    def get_interface_statistics(self, interfaces: List[DBusInterface]) -> Dict[str, any]:
        """
        获取接口统计信息
        
        Args:
            interfaces: 接口列表
            
        Returns:
            统计信息字典
        """
        stats = {
            'total_interfaces': len(interfaces),
            'public_interfaces': len([i for i in interfaces if i.is_public]),
            'total_methods': sum(i.method_count for i in interfaces),
            'total_properties': sum(i.property_count for i in interfaces),
            'total_signals': sum(i.signal_count for i in interfaces),
            'categories': {},
            'namespaces': {},
            'top_interfaces_by_methods': [],
            'top_interfaces_by_properties': [],
        }
        
        # 分类统计
        for interface in interfaces:
            category = interface.category or "未分类"
            stats['categories'][category] = stats['categories'].get(category, 0) + 1
        
        # 命名空间统计
        for interface in interfaces:
            namespace = interface.namespace or "未知"
            stats['namespaces'][namespace] = stats['namespaces'].get(namespace, 0) + 1
        
        # 方法数量排行
        sorted_by_methods = sorted(interfaces, key=lambda i: i.method_count, reverse=True)
        stats['top_interfaces_by_methods'] = [
            {'name': i.name, 'count': i.method_count} 
            for i in sorted_by_methods[:10]
        ]
        
        # 属性数量排行
        sorted_by_properties = sorted(interfaces, key=lambda i: i.property_count, reverse=True)
        stats['top_interfaces_by_properties'] = [
            {'name': i.name, 'count': i.property_count} 
            for i in sorted_by_properties[:10]
        ]
        
        return stats
    
    def validate_interfaces(self, interfaces: List[DBusInterface]) -> List[str]:
        """
        验证接口数据完整性
        
        Args:
            interfaces: 接口列表
            
        Returns:
            验证错误列表
        """
        errors = []
        
        for interface in interfaces:
            # 检查接口名称
            if not interface.name:
                errors.append(f"接口缺少名称: {interface.source_file}")
            
            # 检查方法参数类型
            for method in interface.methods:
                for param in method.input_params + method.output_params:
                    if not param.type_signature:
                        errors.append(
                            f"接口 {interface.name} 方法 {method.name} "
                            f"参数 {param.name} 缺少类型签名"
                        )
            
            # 检查属性类型
            for prop in interface.properties:
                if not prop.type_signature:
                    errors.append(
                        f"接口 {interface.name} 属性 {prop.name} 缺少类型签名"
                    )
        
        return errors
